List of contents

  1. [[#Making REST API Requests]]
  2. [[#DOCKER]]
  3. [[#gRPC]]

Making REST API Requests

GET

public void getAllPersons(CustomerSortingOptions sortingOptions, Consumer<List<Customer>> customerConsumer) {
        webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .path("customers")
                        .queryParam("sortField", sortingOptions.getSortField())
                        .queryParam("sortingOrder", sortingOptions.getSortingOrder())
                        .build())
                .retrieve()
                .bodyToMono(new ParameterizedTypeReference<List<Customer>>() {
                })
                .onErrorStop()
                .subscribe(newPersons -> {
                    customers.clear();
                    customers.addAll(newPersons);
                    customerConsumer.accept(customers);
                });
    }

POST

public void addPerson(Customer customer, Consumer<List<Customer>> customerConsumer) {
    // TODO Part 2: Complete the http post request to the server
    webClient.post()
            .uri("customers")
            .bodyValue(customer)
            .retrieve()
            .bodyToMono(Customer.class)
            .onErrorStop()
            .subscribe(newCustomer -> {
                customers.add(newCustomer);
                customerConsumer.accept(customers);
            });
}

PUT

public void updatePerson(Customer customer, Consumer<List<Customer>> customerConsumer) {
    // TODO Part 2: Complete the http put request to the server
    webClient.put()
            .uri("customers/" + customer.getId())
            .bodyValue(customer)
            .retrieve()
            .bodyToMono(Customer.class)
            .onErrorStop()
            .subscribe(newCustomer -> {
                customers.replaceAll(x -> x.getId().equals(customer.getId()) ? newCustomer : x);
                customerConsumer.accept(customers);
            });
}

DELETE

public void deletePerson(Customer customer, Consumer<List<Customer>> customerConsumer) {
    // TODO Part 2: Make an http delete request to the server
    webClient.delete()
            .uri("customers/" + customer.getId())
            .retrieve()
            .toBodilessEntity()
            .onErrorStop()
            .subscribe(deletedCustomer -> {
                customers.remove(customer);
                customerConsumer.accept(customers);
            });
}

Just in case: webClient Constructor

public CustomerController() {
    this.webClient = WebClient.builder()
            .baseUrl("http://localhost:8080/")
            .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
            .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
            .build();
    this.customers = new ArrayList<>();
}

DOCKER

Docker reference: https://docs.docker.com/

Dockerfiles

https://docs.docker.com/get-started/docker-concepts/building-images/writing-a-dockerfile/ https://docs.docker.com/reference/dockerfile/

FROM python:3.13
WORKDIR /usr/local/app

# Install the application dependencies
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

# Copy in the source code
COPY src ./src
EXPOSE 8080

# Setup an app user so the container doesn't run as the root user
RUN useradd app
USER app

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"]

Building docker

docker build -t <tag>

Docker processes

docker ps

Exercises

gRPC

gRPC reference: https://grpc.io/docs/ gRPC Java basics: https://grpc.io/docs/languages/java/basics/

Defining classes:

message Date {
  int32 day = 1; // Number specifies order
  int32 month = 2;
  int32 year = 3;
}

message Location {
  string city = 1;
  string country = 2;
}

message LocationDate {
  Location location = 1;
  Date date = 2;
}

Defining services:

service WeatherReporter {

  //Returning one object
  rpc GetCityWeatherSingleDay(LocationDate) returns (CityWeatherData) {}

  // Returning a stream of objects
  rpc GetCityWeatherMultipleDays(LocationDatePeriod) returns (stream CityWeatherData) {}
}

Generating classes from .proto files

  1. Gradle tab in IDE and press “Tasks > other > generateProto”)
  2. The generated classes from the proto file should be in build/generated/source/proto/main folder

Implementing gRPC server methods

In practice can be done with streams or with simple iteration

public void getCityWeatherSingleDay(LocationDate request, StreamObserver<CityWeatherData> responseObserver) {
    var data = allWeatherData.stream().filter(cityWeatherData -> cityWeatherData.getLocationDate().equals(request)).findFirst().orElse(null);
    if(data != null)responseObserver.onNext(data);
    responseObserver.onCompleted();
}

For returning a stream of data just call onNext multiple times:

With iteration
public void getCityWeatherMultipleDays(LocationDatePeriod request, StreamObserver<CityWeatherData> responseObserver) {
    for(CityWeatherData data : allWeatherData) {
        if(data.getLocationDate().getLocation().equals(request.getLocation())) {
            if(compareDate(data.getLocationDate().getDate(), request.getStartDate()) >= 0 && compareDate(data.getLocationDate().getDate(), request.getEndDate()) <= 0)
            {
                responseObserver.onNext(data);
            }
        }
    }
    responseObserver.onCompleted();
}
With streams
public void getCityWeatherMultipleDays(LocationDatePeriod request, StreamObserver<CityWeatherData> responseObserver) {
    var startDate = request.getStartDate();
    var endDate = request.getEndDate();
    allWeatherData.stream()
            .filter(cityWeatherData -> cityWeatherData.getLocationDate().getLocation().equals(request.getLocation()))
            .filter(cityWeatherData -> compareDate(cityWeatherData.getLocationDate().getDate(),startDate) >= 0)
            .filter(cityWeatherData -> compareDate(cityWeatherData.getLocationDate().getDate(),endDate) <= 0)
            .forEach(responseObserver::onNext);
    responseObserver.onCompleted();
}